home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Frameworks / Hsoi's App Shell 1.0a4 / Hsoi's App Shell Source / HASUtilDialogs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-28  |  19.6 KB  |  686 lines  |  [TEXT/CWIE]

  1. /*    
  2.     HASUtilDialogs.c from Hsoi's App Shell.  © 1995-1997 John C. Daub.  All rights reserved.
  3.  
  4.     This file contains various dialog utility functions (stuff that's pretty easy to
  5.     reuse as-is in your own code and in various places throughout the shell).
  6.     
  7. */
  8.  
  9. #pragma mark ••• #includes •••
  10.  
  11. #ifndef _WASTE_
  12. #include "WASTE.h"
  13. #endif
  14. #include "HASGlobals.h"
  15. #ifndef __HSOIS_APP_SHELL__
  16. #include "HASMain.h"
  17. #endif
  18. #include "HASUtilDialogs.h"
  19. #include "HASDialogs.h"
  20. #include "HASMiscEvents.h"
  21. #include "HASUtilities.h"
  22. #ifndef _STDIO
  23. #include <stdio.h>
  24. #endif
  25. #ifndef  _STRING
  26. #include <string.h>
  27. #endif
  28.  
  29. #pragma mark -
  30. #pragma mark ••• Std Filter •••
  31.  
  32. // this is our standard, generic dialog filter, used throughout the code (more or less)
  33. // when we need a dialog filter.  you can easily reuse it too, but make sure to
  34. // modify it to fit your needs, and also, make sure that you can use this filter in your
  35. // situation (like we cannot use this for Get/PutFile dialogs.
  36.  
  37.  
  38. pascal Boolean    hsoiMyStandardDialogFilter( DialogRef dialog, EventRecord *event, short *item )
  39. {
  40.     GrafPtr                savePort;
  41.     ModalFilterUPP        stdFilter = nil;
  42.     Boolean                reply = false;
  43.     OSErr                err;
  44.     Boolean                handled = false;
  45.     
  46.     // set up the port
  47.     
  48.     GetPort( &savePort );
  49.     SetGrafPortOfDialog( dialog );
  50.     
  51.     //     intercept window events directed to widnows behind the dialog
  52.     
  53.     if ( ( event->what == updateEvt ) || ( event->what == activateEvt ) )
  54.     {
  55.         if ( (DialogRef)(event->message) != dialog ) 
  56.         {
  57.             if ( event->what == updateEvt )
  58.                 HsoiDoUpdate( (WindowRef)(event->message) );
  59.             else if ( event->what == activateEvt )
  60.                 HsoiDoActivate( (event->modifiers & activeFlag != 0), (WindowRef)(event->message) );
  61.  
  62.         } // end if (WindowPtr)whatEvent != dialog
  63.     
  64.     }
  65.     
  66.     // is the default item a pushbutton?
  67.     
  68.     if ( HsoiGetDialogItemType( dialog, GetDialogDefaultItem(dialog) ) == kButtonDialogItem )
  69.     {
  70.         // yes, so tell the Dialog Manager to care about its outline
  71.     
  72.         err = SetDialogDefaultItem( dialog, GetDialogDefaultItem(dialog));
  73.         if ( err != noErr )
  74.             HsoiDoError( rWindowErrorStrings, strStdDlgFilterSetDef, err, kErrGeneric );
  75.     }
  76.     
  77.     // let's also make sure the cancel button can be handled...now, the cancel button
  78.     // should be dialog item #2.  So, we get dialog item #2, check if it's a button.
  79.     // if it fills these 2 criteria, it's cancel.  Even if the default item and the
  80.     // cancel item are the same, still let them both be set this way so whatever keyboard
  81.     // keys sthe user presses will be handled properly
  82.         
  83.     // remember, this assumes that your cancel item will be item #2 (or at least the item
  84.     // that you want to use for cancelling is #2), and that there are at least 2 items in
  85.     // the dialog to begin with!
  86.     
  87.     if ( HsoiGetDialogItemType( dialog, kStdCancelItemIndex ) == kButtonDialogItem )
  88.     {
  89.         err = SetDialogCancelItem( dialog, kStdCancelItemIndex );
  90.         if ( err != noErr )
  91.             ;  // put error handling in here
  92.     }
  93.     
  94.     
  95.     //    call the standard Dialog Manager filter procedure
  96.     
  97.  
  98.     err = GetStdFilterProc( &stdFilter );
  99.     if ( (err == noErr) && (!handled) )
  100.         reply = CallModalFilterProc( stdFilter, dialog, event, item );
  101.     
  102.     //    restore the port
  103.     SetPort( savePort );
  104.     
  105.     return reply;
  106. }
  107.  
  108. /*
  109.  *    Use this routine to obtain a Universal ProcPtr to the generic dialog filter
  110.  *    (the routine above).  Since it's a global variable, it makes sure it doesn't
  111.  *    already exist (to save some time with mixed mode stuff)
  112.  */
  113.  
  114. pascal ModalFilterUPP HsoiGetMyStandardDialogFilter( void )
  115. {
  116.     if ( gMyStdDlogFilterProc == nil )
  117.         gMyStdDlogFilterProc = NewModalFilterProc(hsoiMyStandardDialogFilter);
  118.     
  119.     return gMyStdDlogFilterProc;
  120. }
  121.  
  122. #pragma mark -
  123. #pragma mark ••• Dlg Item Accessors •••
  124.  
  125. /*
  126.  *  A nice quick routine that gets and returns the itemType of a dialog item
  127.  */
  128.  
  129.  
  130. short    HsoiGetDialogItemType( DialogRef dialog, short item )
  131. {
  132.     short        itemType;
  133.     Handle        itemHandle;
  134.     Rect        itemRect;
  135.  
  136.     GetDialogItem( dialog, item, &itemType, &itemHandle, &itemRect );
  137.     
  138.     return itemType;
  139. }
  140.  
  141. /*
  142.  *    A nice quick routine that returns the Handle to a dialog item
  143.  */
  144.  
  145.  
  146. Handle    HsoiGetDialogItemHandle( DialogRef dialog, short item )
  147. {
  148.     short        itemType;
  149.     Handle        itemHandle;
  150.     Rect        itemRect;
  151.     
  152.     GetDialogItem( dialog, item, &itemType, &itemHandle, &itemRect );
  153.     
  154.     return itemHandle;
  155. }
  156.  
  157. /*
  158.  *    A nice quick routine that returns the Rect of a dialog item
  159.  */
  160.  
  161. void    HsoiGetDialogItemRect( DialogRef dialog, short item, Rect *itemRect )
  162. {
  163.     short        itemType;
  164.     Handle        itemHandle;
  165.     
  166.     GetDialogItem( dialog, item, &itemType, &itemHandle, itemRect );
  167.     
  168.     return;
  169. }
  170.  
  171.  
  172. /*
  173.  *    A nice quick routine that can set a procedure for a dialog item
  174.  */
  175.  
  176. pascal void    HsoiSetDialogItemProc( DialogRef dialog, short item, UserItemUPP proc )
  177. {
  178.     short        itemType;
  179.     Handle        itemHandle;
  180.     Rect        itemRect;
  181.     
  182.     GetDialogItem( dialog, item, &itemType, &itemHandle, &itemRect );
  183.     
  184.     if ( (itemType & 0x007F) == kUserDialogItem )
  185.         SetDialogItem( dialog, item, itemType, (Handle)proc, &itemRect );
  186.     
  187.     return;
  188. }
  189.  
  190. // this will set a dialog item's state to whatever value you pass it (good for
  191. // setting the state of checkboxes, radio buttons, etc)
  192.  
  193. void    HsoiSetDialogItemState( DialogRef dlg, short controlNumber, short value )
  194. {
  195.     Handle    iHandle;
  196.     
  197.     iHandle = HsoiGetDialogItemHandle( dlg, controlNumber );
  198.     SetControlValue( (ControlRef)iHandle, value );
  199.  
  200.     return;
  201. }
  202.  
  203. // tho this routine is really only useful in the big modal dialog sample, it can
  204. // give you can idea of a way to handle radio buttons.
  205.  
  206.  
  207. void    HsoiSetRadioButton( DialogRef dlg, short buttonNumber )
  208. {
  209.     if ( buttonNumber != gCurrentRadio )
  210.     {
  211.         if ( gCurrentRadio != 0 )
  212.             HsoiSetDialogItemState( dlg, gCurrentRadio, 0 );
  213.         
  214.         gCurrentRadio = buttonNumber;
  215.         
  216.         if ( ( gCurrentRadio >= kRadioButtonFirst ) && ( gCurrentRadio <= kRadioButtonLast ) )
  217.             HsoiSetDialogItemState( dlg, gCurrentRadio, 1 );
  218.     }
  219.     
  220.     return;
  221. }
  222.  
  223. // BorderDefault draws a heavy border around the default button (in this case the OK button )
  224. // Again, not necessary if the new DM calls are in (i.e. not necessary for Hsoi's App Shell,
  225. // but I'm leaving it in the code just in case you're someone that might be interested
  226. // in knowing how to do this sort of thing)
  227.  
  228. pascal void HsoiBorderDefault(WindowRef dwind, short dinum)
  229. {
  230. #pragma unused (dinum)
  231.  
  232.     Rect borderRect;
  233.  
  234.     HsoiGetDialogItemRect( dwind, ok, &borderRect );
  235.  
  236.     // ok is defined as 1 in the interfaces.  If you'd like another item outlined,
  237.     // change this number, of course.
  238.  
  239.     InsetRect(&borderRect, -4, -4);
  240.     PenSize(3, 3);
  241.     FrameRoundRect(&borderRect, 16, 16);
  242.     PenSize(1, 1);
  243.     
  244.     return;
  245. } // end BorderDefault
  246.  
  247.  
  248.  
  249. // a little utility to see if the current key is an edit-type key
  250.  
  251. Boolean HsoiIsEditKey(char theKey, short modifiers)
  252. {
  253.     register qq;
  254.     Boolean returnVal = false;
  255.     char editChars[] = 
  256.     {
  257.         kLeftArrow, kUpArrow, kRightArrow, kDownArrow, kBackSpace, kEscKey
  258.     };
  259.     char commandEdits[] =
  260.     {
  261.         'C', 'V', 'X'  //  for some reason, in the original DialogBits, C.K. Haun
  262.                         //    had C, V and P in here...go figure?
  263.     };
  264.     
  265.     for (qq = 0; qq < sizeof(editChars) / sizeof(char); qq++)
  266.     {
  267.         if (theKey == editChars[qq])
  268.             returnVal = true;
  269.     }
  270.     if (returnVal != true && (modifiers & cmdKey)) 
  271.     {
  272.         // check for XCP
  273.         // Do you want me to use toupper?  What! And link in all of StdLib! aggggg
  274.     
  275.         if (theKey >= 0x61 && theKey <= 0x7a)
  276.             theKey -= 0x20;
  277.         for (qq = 0; qq < sizeof(commandEdits) / sizeof(char); qq++)
  278.         {
  279.             if (theKey == commandEdits[qq])
  280.                 returnVal = true;
  281.         }
  282.     }
  283.     return(returnVal);
  284. } // end IsEditKey
  285.  
  286.  
  287. // Gets the ControlHandle for the item you want in the dialog box thebox.
  288. // Handy for setting checkboxes and radio buttons
  289. // This is the _most_ copied routine from this file
  290.  
  291. ControlRef HsoiSnatchHandle(DialogRef thebox, short theGetItem)
  292. {
  293.     Handle thandle;
  294.     
  295.     thandle = HsoiGetDialogItemHandle( thebox, theGetItem );
  296.     return((ControlRef)thandle);
  297.  
  298. } // end SnatchHandle
  299.  
  300.  
  301. //COPLAND - this entire function breaks under STRICT macros cause of how it 
  302. //takes a DialogPeek as an argument, and how it accesses elements of a DialogRecord,
  303. // all things which will no longer exist under Copland
  304. short HsoiHasSelectionRange(DialogPeek inputDialog)
  305. {
  306.     TEHandle theTERecord = inputDialog->textH;
  307.     short returnVal = (*theTERecord)->selEnd -(*theTERecord)->selStart;
  308.     
  309.     return(returnVal);
  310. } // end HasSelectionRange
  311.  
  312.  
  313.  
  314. // this function draws a nice little "frame" around dialog items.  for items in
  315. // dialogs that you'd like grouped together (e.g. a group of related radio buttons)
  316. // you can create a user item in the DITL to group these together.  then, install
  317. // this function as a user item proc (UserItemUPP) for that user item and it'll
  318. // draw a nice little frame around them.
  319.  
  320. pascal void    HsoiDrawGroupBox( WindowRef dialog, short item )
  321. {
  322.     GrafPtr            savePort;
  323.     Rect            r;
  324.     
  325.     // get and save the old port
  326.     
  327.     GetPort( &savePort );
  328.     
  329.     // set the port to our dialog
  330.     
  331.     SetPort( dialog );    
  332.     
  333.     // get the rect for the user item
  334.     
  335.     HsoiGetDialogItemRect( dialog, item, &r );
  336.     
  337.     // frame it up
  338.     
  339.     FrameRect( &r );
  340.     
  341.     // and restore the old port
  342.     
  343.     SetPort( savePort );
  344.     
  345.     return;
  346. }
  347.  
  348. // this is very similar in function to HsoiSetDialogItemState, except we take a Boolean
  349. // instead of a short.  It can just allow for more readable code.
  350.  
  351. void    HsoiDlgSetCheck( DialogRef dlg, short item, Boolean value )
  352. {
  353.     Handle    itemHandle;
  354.     
  355.     itemHandle = HsoiGetDialogItemHandle( dlg, item );
  356.     SetControlValue((ControlRef)itemHandle,value);
  357.     
  358.     // since this is so similar to HsoiSetDialogItemState, if we just wanted to have
  359.     // HsoiDlgSetCheck exist purely to create more readable code, we could change
  360.     // this function to be only one line:
  361.     
  362.     // HsoiSetDialogItemState( dlg, item, (short)value );
  363. }
  364.  
  365. // this will return the state of a checkbox: return true for on, false for off.
  366.  
  367. Boolean     HsoiDlgGetCheck (DialogRef dlg, short item)
  368. {
  369.     Handle     itemHandle;
  370.  
  371.     itemHandle = HsoiGetDialogItemHandle( dlg, item );
  372.     return (GetControlValue((ControlRef)itemHandle) == 1);
  373. }
  374.  
  375. // whatever the current setting of a checkbox, this will flip it to the other
  376.  
  377. void     HsoiDlgToggleCheck(DialogRef dlg, short item)
  378. {
  379.     Handle     itemHandle;
  380.     short     value;
  381.     
  382.     itemHandle = HsoiGetDialogItemHandle( dlg, item );
  383.     value = (GetControlValue((ControlRef)itemHandle) == 1) ? 0 : 1;
  384.     SetControlValue((ControlRef)itemHandle,value);
  385.     
  386.     return;
  387. }
  388.  
  389. Boolean        HsoiDlgGetRadio( DialogRef dlg, short item )
  390. {
  391.     // same thing as HsoiDlgGetCheck() in concept, so we'll just call that function
  392.     // but this gives it a more readable name for the usage
  393.     
  394.     return ( HsoiDlgGetCheck( dlg, item ) );
  395. }
  396.  
  397. // yet another function that will return a ControlRef of a dialog item.
  398. // HsoiSnatchHandle and typecasting the return of HsoiGetDialogItemHandle
  399. // (i.e. (ControlRef)HsoiGetDialogItemHandle()) will all do the same thing.
  400.  
  401. ControlRef    HsoiDlgGetControl (DialogRef dlg, short item)
  402. {
  403.     Handle         itemHandle;
  404.     
  405.     itemHandle = HsoiGetDialogItemHandle( dlg, item );
  406.     return (ControlRef)itemHandle;
  407. }
  408.  
  409. // this will set the text of a dialog item to a value that you pass it
  410.  
  411. void    HsoiDlgSetNumber (DialogRef dlg, short item, short value)
  412. {
  413.     Handle         itemHandle;
  414.     Str255         valStr;
  415.     
  416.     NumToString(value, valStr);
  417.     itemHandle = HsoiGetDialogItemHandle( dlg, item );
  418.     SetDialogItemText(itemHandle, valStr);
  419.     
  420.     return;
  421. }
  422.  
  423.  
  424. // this will get the text of a dialog item (returned in "value" as a Pascal string)
  425.  
  426. void    HsoiDlgGetPString( DialogRef dlg, short item, StringPtr value )
  427. {
  428.     Handle        itemHandle;
  429.  
  430.     itemHandle = HsoiGetDialogItemHandle( dlg, item );
  431.     GetDialogItemText( itemHandle, value );
  432.     
  433.     return;
  434. }
  435.  
  436. // and this will set a dialog item's text to a given Pascal string
  437.  
  438. void    HsoiDlgSetPString( DialogRef dlg, short item, StringPtr value )
  439. {
  440.     Handle        itemHandle;
  441.  
  442.     itemHandle = HsoiGetDialogItemHandle( dlg, item );
  443.     SetDialogItemText( itemHandle, value );
  444.     
  445.     return;
  446. }
  447.  
  448.  
  449.  
  450.  
  451. /*
  452.     This function, HsoiGetDoubleItem(), was given to me by Scott Pogorelc.  It's a nice
  453.     little way to get a floating point value from a dialog item.  Since all numbers in
  454.     dialogs are really in Str255's, we need a nice way to convert the number as a string
  455.     to a number as a number.  For whole numbers, we usually do this same thing, but
  456.     then just call StringToNum() to convert it.
  457.     
  458.     Unfortuately, StringToNum (and NumToString) only work on whole numbers.  For
  459.     real numbers (i.e. w/ decimals), we can't do this.  There is a nice toolbox
  460.     routine called StringToExtended that takes care of floating point numbers.
  461.     (they used to be called, FormatX2Str() and FormatStr2X() and if you're looking
  462.     these routines up in THINK Ref (>= 2.0.1), they're under these names)
  463.     
  464.     The nice thing about this is that 1. is does what we need, 2. it doesn't require
  465.     ANSI C library functions and hence the need to link in the ANSI libs.
  466.     
  467.     And there is another bonus to using StringToExtended...it's localizable.  Not
  468.     everywhere in the world do they use a comma as the thousands seperator and
  469.     a period as the decimal seperator (as we do in the USA, e.g. 1,234,567.890).
  470.     StringToExtended can take these things into account and make sure that your
  471.     number manipulations all work right.
  472.     
  473.     However, this is also a reason why I am not using StringToExtended.
  474.     
  475.     Due to the fact that you have to do all this junk to deal with the international
  476.     ways of being, there's a lot of "overhead" IMHO.  It's really not all that
  477.     hard, but it's just stuff I don't want to deal with (i'm being lazy).  Plus,
  478.     how much need for this is there?  Since these functions (within the scope of HAS)
  479.     are just being used for the print options dialog to get the margins setting,
  480.     and the fact that the margins are in inches, I don't think we it's all THAT
  481.     necessary to worry about localization (where else in the world do they use
  482.     inches but the USA?  anyone using inches as their measurement ought to know
  483.     to use a period as the decimal seperator.  besides, as it stands now, HAS
  484.     is localized for the USA anyways). (some of this reasoning came out of a
  485.     discussion I had with Tom Bender, the author of the code this is all based upon.
  486.     if this reasoning is wrong, please let me know so I can pass the world along
  487.     to Tom also).
  488.     
  489.     So, even tho the standard ANSI C library functions don't take any localization
  490.     into account (they're US localized, if you will), they do the job.
  491.     
  492.     Plus, StringToExtended does just that...converts a string to an extended variable.
  493.     extended's are part of Apple's SANE method of handling real numbers.  SANE isn't
  494.     all that happy with PowerMacs (the PowerPC chip) (that's part of the reason Apple
  495.     is attempting to phase in fp.h in place of SANE.h).  So, trying to use StringToExtended
  496.     could cause you problems based on the chip and also if you generate 68881 instructions
  497.     or not.
  498.     
  499.     I found a "smarter" way of dealing with StringToExtended in "develop" magazine's
  500.     Q&A section.  You can find these in HASUtilities.c as HsoiStringToExtended() and
  501.     HsoiExtendedToString().
  502.     
  503.     If you'd like to use StringToExtended (or ExtendedToString), you'll want
  504.     to check out Inside Macintosh: Text.  it's in Chapter 5 i think.  tells
  505.     all about it.
  506.     
  507.     In a future release of HAS, i'll probably rewrite all this relevant stuff
  508.     with StringToExtended to show how to use it all (but leave it just as
  509.     commented out code so as not to cause compiler conflicts).  Lemme know
  510.     if you're interested in this sort of thing.
  511.     
  512.     whew!  long explanation, but I hope I covered all the relevant stuff :)
  513.  
  514. */
  515.  
  516. double HsoiGetDoubleItem( DialogRef dialog, short item )
  517. {
  518.     Handle        itemHandle;
  519.     Str255        itemText = {0}; // make sure it's a null terminated string
  520.     double        value;
  521.         
  522.     itemHandle = HsoiGetDialogItemHandle( dialog, item );
  523.     
  524.     GetDialogItemText( itemHandle, itemText );
  525.  
  526.     // ignore the length byte as we convert the string to a double
  527.     
  528.     sscanf( (char *)itemText + 1, "%lf", &value );
  529.  
  530.     return value;
  531. }
  532.  
  533. // extract the numeric value from a dialog editable text item.  returns legal = true if
  534. // result is in the given range of values (lo...hi).  Decimals are stripped/ignored
  535.  
  536. void    HsoiGetDialogItemValue( DialogRef dlg, short item, double lo, double hi, Boolean *legal, double *result )
  537. {
  538.     short            i = 1;
  539.         
  540.     // assume it'll be legal
  541.         
  542.     *legal = true;
  543.     
  544.     // get the the numeric "equivalent" of the dialog's text
  545.     
  546.     *result = HsoiGetDoubleItem( dlg, item );
  547.     
  548.     // see if it's out of range
  549.     
  550.     if ( (*result < lo) || (*result > hi) )
  551.     {
  552.         *legal = false;
  553.         if ( *result < lo )
  554.             *result = lo;
  555.         else if ( *result > hi )
  556.             *result = hi;
  557.         else // things go silly
  558.             *result = lo; // arbitrary choice
  559.     }
  560.     
  561.     return;
  562.     
  563. }
  564.  
  565. // handles the mouseDowns in the little up/down arrow controls
  566.  
  567. void    HsoiDoArrowUpDown( DialogRef dlg,             /* the dialog we're doing this in */
  568.                             short itemHit,            /* the total arrow rect user item # */
  569.                             short editTxtItem,        /* the edit text box associated with this */
  570.                             short arrowRectItem,    /* the little arrow user item rect */
  571.                             double increment,        /* the amount to increment by (can be negative
  572.                                                         values for a decrement) */
  573.                             double loLimit,            /* the lower limit of the control */
  574.                             double hiLimit,            /* the upper limit of the control */
  575.                             Boolean isFraction,        /* do we want real numbers or whole numbers? */
  576.                             double *variable )        /* pointer to the actual value */
  577. {
  578.     
  579.     GrafPtr            savePort;
  580.     long            xx;
  581.     Rect            arrowRect;    // rect of entire arrow picture
  582.     Rect            selectedRect;    // area chosen (up or down area)
  583.     Handle            arrowHdl, arrowUpDnHdl;
  584.     Handle            editTxtHdl;
  585.     Str255            s, s2;
  586.     Point            mLoc; // mouseDown location
  587.     short            wait;
  588.     
  589.     // get and set the ports
  590.     
  591.     GetPort( &savePort );
  592.     SetGrafPortOfDialog( dlg );
  593.     
  594.     // get the selected/total arrow rects
  595.     
  596.     HsoiGetDialogItemRect( dlg, itemHit, &selectedRect );
  597.     HsoiGetDialogItemRect( dlg, arrowRectItem, &arrowRect );
  598.     
  599.     // get plain/selected icons
  600.     
  601.     arrowHdl = GetIcon( rUpDownArrowIcon );
  602.     if ( increment > 0 )
  603.         arrowUpDnHdl = GetIcon( rUpArrowIcon );
  604.     else
  605.         arrowUpDnHdl = GetIcon( rDownArrowIcon );
  606.     
  607.     // draw the icon and select the related text box
  608.     
  609.     editTxtHdl = HsoiGetDialogItemHandle( dlg, editTxtItem );
  610.     PlotIcon( &arrowRect, arrowUpDnHdl );
  611.     SelectDialogItemText( dlg, editTxtItem, 0, 0 );
  612.     
  613.     // decrement wait in loop to speed up dragually
  614.     
  615.     wait = kDelayTime;
  616.     
  617.     // continue incrementing text value until mouseUp
  618.     
  619.     do
  620.     {
  621.         GetMouse( &mLoc );
  622.         
  623.         // continue while mouse stays in selectedRect
  624.         
  625.         if ( PtInRect( mLoc, &selectedRect ) )
  626.         {
  627.             PlotIcon( &arrowRect, arrowUpDnHdl );
  628.             
  629.             // increment, but keep variable in range
  630.             
  631.             *variable += increment;
  632.                 if ( *variable < loLimit )
  633.                     *variable = loLimit;
  634.                 else if ( *variable > hiLimit )
  635.                     *variable = hiLimit;
  636.  
  637.             // convert our amount into a string for easier manipulation
  638.             
  639.             if ( isFraction )
  640.                 // gives us a precision of 2 decimal places
  641.                 sprintf( (char *)s + 1, "%.2lf", *variable );
  642.             else
  643.                 // gives us a precision of zero decimal places (i.e. no decimal,
  644.                 // nor nothing after it...a "whole" number)
  645.                 sprintf( (char *)s + 1, "%.lf", *variable );
  646.                 
  647.             // just make sure the length byte [0] isn't the null character
  648.             s[0] = 1; // arbitrary choice
  649.             s[0] = strlen( (char *)s ) - 1; // minus 1 for that above arbitrary non-null stuff
  650.             
  651.             // and put this new value in the dialog, first making sure of
  652.             // what's already in there
  653.             
  654.             GetDialogItemText( editTxtHdl, s2 );
  655.             if ( !EqualString( s, s2, false, false ) )
  656.                 SetDialogItemText( editTxtHdl, s );
  657.             
  658.             // speed up incrementation
  659.             
  660.             if ( wait > 1 )
  661.                 wait -= 1;
  662.             
  663.             if ( StillDown() )
  664.                 Delay( wait, &xx );
  665.         
  666.         } // end: if (PtInRect(mLoc, &selectedRect))
  667.         
  668.         else // mouse out of rect.  draw unselected picture
  669.             PlotIcon( &arrowRect, arrowHdl );
  670.         
  671.     } 
  672.     while ( StillDown() );
  673.     
  674.     // hilite text and draw unselected picture
  675.     
  676.     SelectDialogItemText( dlg, editTxtItem, 0, MAXLONG );
  677.     PlotIcon( &arrowRect, arrowHdl );
  678.     
  679.     SetPort( savePort );
  680.     
  681.     return;
  682.     
  683. }
  684.  
  685.  
  686.